Форум dkLab и Denwer
Здесь общаются Web-разработчики.
Генеральный спонсор:
Хостинг «Джино»

Проектирование простейшего (!) модуля для абстракции от SQL-сервера. (Дмитрий Котеров)
Goto page Previous  1, 2
Author Message
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 414
   поощрить/наказать


PostPosted: Thu Aug 25, 2005 5:22 pm (написано за 1 минуту 2 секунды)
   Post subject:
Reply with quote

dacuan wrote:
COUNT_TOTAL
Вот тут случайно наткнулся. Оказывается, в MySQL 4.0 это уже реализовано и называется SQL_CALC_FOUND_ROWS:
Code (SQL): скопировать код в буфер обмена
SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name WHERE id > 100 LIMIT 10;
SELECT FOUND_ROWS();
Соответственно, можно реализовать через него.
Back to top
View user's profile Send private message Send e-mail
dacuan
Участник форума



Joined: 16 Mar 2005
Posts: 20
Карма: 0
   поощрить/наказать


PostPosted: Mon Aug 29, 2005 10:59 am (спустя 3 дня 17 часов 36 минут; написано за 1 минуту)
   Post subject:
Reply with quote

Дмитрий Котеров wrote:
Соответственно, можно реализовать через него.
Если используется MySQL старше 4-й версии, а если младше, то реализовать прозрачную эмуляцию ;)
Back to top
View user's profile Send private message
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 414
   поощрить/наказать


PostPosted: Fri Sep 02, 2005 1:38 pm (спустя 4 дня 2 часа 38 минут; написано за 2 минуты 54 секунды)
   Post subject:
Reply with quote

Конец уже близок - библиотека используется в 4 проектах (2 на MySQL, 2 на Ibase).
dklab.ru/lib/DbSimple/demo/
dklab.ru/lib/DbSimple/demo.zip

Пример использования (файл connect.php одного из проектов):
Code (php): скопировать код в буфер обмена
<?php
/*
require_once dirname (www.php.net/dirname)(__FILE__).'/config.php';
require_once "DbSimple/DSN.php";

//
$DATABASE = DbSimple_DSN::connect(DB_DSN);
$DATABASE->set_error_handler('cmf_databaseErrorHandler');

//
$DATABASE->setLogger('cmf_sqlQueryLogger');

//
//
//
$GLOBALS['DB'] = $DATABASE->transaction();

/*
function cmf_databaseErrorHandler($message, $info)
{
        // If @ is used, ignore errors.
        if (!error_reporting (www.php.net/error_reporting)()) return null;
       
        $GLOBALS['info'] = $info;
        require_once "string.php";

        if (is_callable (www.php.net/is_callable)($f='ob_page_clean')) $f();
               
        if (DEBUG_MODE) {
                include_html('_debug_dberror');
        } else {
                include_html('_release_dberror');
        }
        exit (www.php.net/exit);
}


/*
function cmf_sqlQueryLogger($db, $sql)
{
        require_once "string.php";
        
        $color = null;
        if (!preg_match (www.php.net/preg_match)('/^\s*--/', $sql)) {
                $sql = removeSpacePrefixes($sql);
        } else {
                $color = '#00AA00';
        }
        $sql = $sql.";";
        if (DEBUG_MODE) {
                $callers = $db->findLibraryCaller();
                $caller = $callers[0];
                $tip = "at ".@$caller['file'].' line '.@$caller['line'];
        }
        debug($sql, "SQL", $color, $tip);
}


/*
function Sql2Array($sql)
{
        global (www.php.net/global) $DB; $params = func_get_args (www.php.net/func_get_args)();
        return call_user_func_array (www.php.net/call_user_func_array)(array (www.php.net/array)(&$DB, 'select'), $params);
}

function Sql()
{
        global (www.php.net/global) $DB; $params = func_get_args (www.php.net/func_get_args)();
        return call_user_func_array (www.php.net/call_user_func_array)(array (www.php.net/array)(&$DB, 'selectRow'), $params);
}

function SqlSingle()
{
        global (www.php.net/global) $DB; $params = func_get_args (www.php.net/func_get_args)();
        return call_user_func_array (www.php.net/call_user_func_array)(array (www.php.net/array)(&$DB, 'selectCell'), $params);
}

function SqlCol()
{
        global (www.php.net/global) $DB; $params = func_get_args (www.php.net/func_get_args)();
        return call_user_func_array (www.php.net/call_user_func_array)(array (www.php.net/array)(&$DB, 'selectCol'), $params);
}
?>
Очень удобно использовать совместно с Debug_HackerConsole (forum.dklab.ru/php/advises/Debug_hackerconsoleTheHackerConsoleForAConclusionOfDebuggingMessages.html) для логирования всех запросов, сгенерированных скриптом (см. скриншот). Выводится также статистика запросов (сколько времени выполнялся, что вернул).


pic17.gif
 Description:
 Filesize:  114.13 KB
 Viewed:  803 Time(s)

pic17.gif
Щелкните, чтобы посмотреть полноразмерное изображение.



Back to top
View user's profile Send private message Send e-mail
alexhemp
Участник форума



Joined: 31 Aug 2005
Posts: 29
Карма: 2
   поощрить/наказать


PostPosted: Wed Sep 07, 2005 1:05 pm (спустя 4 дня 23 часа 27 минут; написано за 5 минут 6 секунд)
   Post subject:
Reply with quote

Дмитрий Котеров

Дмитрий! А вы не думали над включением в класс ф-ций типа insert(string $table, array $values), update(string $table, array $values, array $where), delete(string $table, array $where)

Это позволяет записывать в базу без написания однотипных операторов, которые в большинстве своем на порядок проще чем SELECT.

Просто передаем ассоциативный массив (для INSERT можно массив строк) и получаем на выходе запрос или просто его выполняем.

Интересует ваше мнение, за и против так сказать ;-)

P.S. Кстати в архиве DbSimple нет файла DSN.php, не могли бы Вы его тоже выложить :-)
Back to top
View user's profile Send private message
XNic
Заглянувший



Joined: 08 Sep 2005
Posts: 1
Карма: 0
   поощрить/наказать


PostPosted: Thu Sep 08, 2005 10:29 am (спустя 21 час 23 минуты; написано за 4 минуты 57 секунд)
   Post subject:
Reply with quote

А для чего нужны функции выборки первого столбца? Еще в SQL запросе нужно писать только один выбираемы столбец.
Это, я бы сказал, не модуль абстракии от БД, а модуль абстракции от интерфейса БД (набора функций). Когда-то у меня было что-то подобное (кстати, делал MySql/IB/MSSQL) - хватало для совместимости
1. выборки результата в ассоциативный массив (db_array_query)
2. Версии (1-ой) функции - выборка строго одного ряда - если больше рядов, ошибка (вроде ассерта)
3. подключение/отключение БД
4. и старый интерфейс - выполнить запрос, получить ряд, позиционировать
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 414
   поощрить/наказать


PostPosted: Thu Sep 08, 2005 11:16 am (спустя 46 минут; написано за 7 минут 51 секунду)
   Post subject:
Reply with quote

alexhemp wrote:
в архиве DbSimple нет файла DSN.php
Да, действительно. Совсем забыл выложить. Сейчас выложил.
alexhemp wrote:
А вы не думали над включением в класс ф-ций типа insert(string $table, array $values), update(string $table, array $values, array $where), delete(string $table, array $where)
Ни в коем случае нельзя этого делать! Это несколько противоречит идеологии класса, а кроме того, сильно снижает универсальность (например, можно делать insert...select или update...join или delete...join в MySQL4).

К счастью, универсальное решение есть:
Code (php): скопировать код в буфер обмена
$row = array (www.php.net/array)('id'=>5, 'field1'=>'value1', ...);
$DB->query('INSERT INTO a SET ?a', $row);
$DB->query('UPDATE a SET ?a WHERE id=?', $row, $row['id']);
//
 
Работа со списками:
Code (php): скопировать код в буфер обмена
$ids = array (www.php.net/array)(1, 3, 6, 88);
$rows = $DB->select('SELECT * FROM a WHERE id IN(?a)', $ids);
XNic wrote:
А для чего нужны функции выборки первого столбца?
Например, для выборки разных справочников:
Code (php): скопировать код в буфер обмена
$uniq = $DB->selectCol('SELECT DISTINCT surname FROM people'); // список
$cities = $DB->selectCol('SELECT city_id AS ARRAY_KEY, city_name FROM city'); // хэш
 
XNic wrote:
Это, я бы сказал, не модуль абстракии от БД, а модуль абстракции от интерфейса БД
Совершенно верно.
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 414
   поощрить/наказать


PostPosted: Thu Sep 08, 2005 11:20 am (спустя 4 минуты; написано за 3 минуты 18 секунд)
   Post subject:
Reply with quote

А еще я забыл сказать: класс поддерживает выборку древовидных структур, когда таблица имеет вид (ID, PID, ...), по аналогии с тем, как это делается для ассоциативных структур (ARRAY_KEY). Например:
Code (php): скопировать код в буфер обмена
$forest = $DB->select('SELECT tree_id AS ARRAY_KEY, tree_pid AS PARENT_KEY, * FROM tree'); //
 
Зарезервиврованное имя сторлбца PARENT_KEY задает поле, в котором хранится parent id, а ARRAY_KEY - поле, задающее ID записи. Данные выбираются в виде вложенных ассоциативных массивов (ключ childNodes).

Что еще планируется сделать:
- для тех баз, где есть native-поддержка placeholder-ов (например, ibase), - задействовать ее для скалярных полей (?a по-прежнему обрабатывается обычным образом); при этом логирование должно работать по-прежнему;
- поддержка prepare+execute, но на "невидимом" уровне (если в двух идущих подряд запросах совпадает текст запроса ДО подстановки placeholder-ов, значит, имеет смысл 1 раз сделать prepare, а в следующие разы - только execute; внейший интерфейс библиотеки от этого не меняется, а прирост скорости при выполнении множества однотипных запросов будет значительный);
- исключить издержки на логирование, если функция-логгер не назначена (сейчас накладные расходы имеются, хотя и не очень большие).
Back to top
View user's profile Send private message Send e-mail
alexhemp
Участник форума



Joined: 31 Aug 2005
Posts: 29
Карма: 2
   поощрить/наказать


PostPosted: Thu Sep 08, 2005 1:02 pm (спустя 1 час 41 минуту; написано за 1 минуту 56 секунд)
   Post subject:
Reply with quote

Дмитрий Котеров

А разве FireBird/Interbase поддерживают синтаксис INSERT SET ?

Ну правда можно вывернуться передав отдельно array_keys и array_values...

А скажите, синтаксис плейсхолдеров совпадает с Database_Placeholder который вот здесь выложен?
dklab.ru/lib/Database_Placeholder/
Back to top
View user's profile Send private message
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 414
   поощрить/наказать


PostPosted: Thu Sep 08, 2005 2:37 pm (спустя 1 час 35 минут; написано за 1 минуту 40 секунд)
   Post subject:
Reply with quote

alexhemp wrote:
А разве FireBird/Interbase поддерживают синтаксис INSERT SET
А черт его знает, кстати. Ни разу не пробовал - у нас все через хранимые процедуры делается, INSERT не используем.
Но, если не поддерживает, - да, придется делать как-то так:
Code (php): скопировать код в буфер обмена
$DB->query('INSERT INTO a (?ak) VALUES (?av)', $row);
alexhemp wrote:
синтаксис плейсхолдеров совпадает с Database_Placeholder который вот здесь выложен?
Да, конечно!
Back to top
View user's profile Send private message Send e-mail
alexhemp
Участник форума



Joined: 31 Aug 2005
Posts: 29
Карма: 2
   поощрить/наказать


PostPosted: Thu Sep 08, 2005 3:17 pm (спустя 40 минут; написано за 4 минуты 34 секунды)
   Post subject:
Reply with quote

Дмитрий Котеров
Я заметил что там используется ?@ а тут ?a

По поводу синтаксиса, я посмотрел, IB6 не поддерживает SET синтаксис для INSERT

Я пожалуй все-таки напишу свою прослойку для простейших insert, update, delete ;-)
Они одинаковы для всех серверов и их можно прямо в абстрактном классе написать.

Для простых случаев мне их будет удобно использовать. А для сложных можно как вы предлагается...

Хочется чтобы приложение легко могло использовать mysql 4.x и firebird 1.x, без правки кода. Хранимые процедуры не будем использовать ибо в mysql их пока нет...
Back to top
View user's profile Send private message
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 414
   поощрить/наказать


PostPosted: Thu Sep 08, 2005 3:30 pm (спустя 12 минут; написано за 1 минуту 1 секунду)
   Post subject:
Reply with quote

alexhemp wrote:
Я пожалуй все-таки напишу свою прослойку для простейших insert, update, delete ;-)
Они одинаковы для всех серверов и их можно прямо в абстрактном классе написать.
Я не понимаю, зачем это делать. Синтаксис insert, update и delete на том уровне, на котором Вы его хотите эмулировать, и так един для всех СУБД (это стандарт SQL'92). Таким образом, введением трех неуниверсальных методов Вы ничего нового не получите, только код загромоздите.
Back to top
View user's profile Send private message Send e-mail
alexhemp
Участник форума



Joined: 31 Aug 2005
Posts: 29
Карма: 2
   поощрить/наказать


PostPosted: Thu Sep 08, 2005 3:41 pm (спустя 10 минут; написано за 4 минуты 2 секунды)
   Post subject:
Reply with quote

Дмитрий Котеров

Ну я еще подумаю :-) Мне пока кажется что будет проще, банально что-бы не писать INSERT INTO и DELETE FROM каждый раз.

Для INSERT у меня часто используется такой синтаксис

INSERT INTO table(field1, field2) VALUES('val1', 'val2'), ('val3', 'val4') ... ('valN', 'valM')

Т.е. формируется массив какой-то пришедший от юзера и одним махом его в базу.

$db->insert('table', array(...));

Но безусловно можно переписать на несколько insert-ов. Собствеенно я поэтому и задал этот вопрос, потому что мне показалось, что такие ф-ции избыточны, но хочется быть уверенным ;-)
Back to top
View user's profile Send private message
Дамир Хуснатдинов
Заглянувший



Joined: 31 Mar 2005
Posts: 8
Карма: 1
   поощрить/наказать

Location: Новосибирск

PostPosted: Fri Sep 09, 2005 9:44 am (спустя 18 часов 3 минуты; написано за 3 минуты 35 секунд)
   Post subject:
Reply with quote

Дмитрий Котеров wrote:
- для тех баз, где есть native-поддержка placeholder-ов (например, ibase), - задействовать ее для скалярных полей (?a по-прежнему обрабатывается обычным образом); при этом логирование должно работать по-прежнему;
Или например MySQL 4.1+: dev.mysql.com/doc/mysql/en/sqlps.html
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 414
   поощрить/наказать


PostPosted: Mon Oct 03, 2005 6:18 pm (спустя 24 дня 8 часов 33 минуты; написано за 5 минут 38 секунд)
   Post subject:
Reply with quote

Новая версия 1.21. Утрачена совместимость с предыдущими версиями (в некоторых аспектах, не очень значительных). Новые возможности:
- Поддержка "родных" placeholder-ов ibase.
- Поддержка оптимизации "1 prepare - куча execute" для запросов, полностью совпадающих друг с другом (за исключением значений placeholder-ов, естественно).
- Оптимизация скорости работы в release-режиме (логирование можно не включать, это убыстрит работу).
- Изменен синтаксис selectPage(): mixed selectPage(int &$total, string $query [, $arg1] [,$arg2] ...). Теперь LIMIT-ы нужно задавать прямо в теле запроса (обычным для СУБД способом), а selectPage их потом вырежет, когда ей это понадобится.

Теперь библиотека ВООБЩЕ не обеспечивает абстракции от реализации SQL-диалекта. Это изначально не было ее задачей, поэтому selectPage с тремя параметрами смотрелись уродливо. Теперь их нет.

Полный API транзакции:

mixed query(string $query [, $arg1] [,$arg2] ...)
mixed select(string $query [, $arg1] [,$arg2] ...) // синоним query()
mixed selectPage(int &$total, string $query [, $arg1] [,$arg2] ...)
hash selectRow(string $query [, $arg1] [,$arg2] ...)
array selectCol(string $query [, $arg1] [,$arg2] ...)
scalar selectCell(string $query [, $arg1] [,$arg2] ...)

mixed commit()
mixed rollback()
resource id()
bool setBlobFetchMode($needFetchBlobs=true)


В будущем вряд ли будет меняться.
Back to top
View user's profile Send private message Send e-mail
Сергей Комов
Участник форума



Joined: 10 Oct 2004
Posts: 54
Карма: 2
   поощрить/наказать


PostPosted: Thu Nov 03, 2005 9:02 am (спустя 30 дней 14 часов 44 минуты; написано за 1 минуту 47 секунд)
   Post subject:
Reply with quote

Дмитрий Котеров
Как с помощью плейсхолдеров вставить в запрос константу? Раньше с помощью плейсхолдеров описанных в набле, делал так: ?#CONST, сейчас это не работает в классе.
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 414
   поощрить/наказать


PostPosted: Thu Nov 03, 2005 7:27 pm (спустя 10 часов 25 минут; написано за 33 секунды)
   Post subject:
Reply with quote

В данной библиотеке - никак нельзя вставить, разрывайте строку.
Back to top
View user's profile Send private message Send e-mail
Иван Шумков
Участник форума



Joined: 30 Dec 2004
Posts: 229
Карма: 6
   поощрить/наказать

Location: Россия, Санкт-Петербург

PostPosted: Fri Nov 04, 2005 4:55 pm (спустя 21 час 27 минут; написано за 24 секунды)
   Post subject:
Reply with quote

Поечему не сделаете поддержку "родных" placeholder-ов mysql?
Back to top
View user's profile Send private message
Сергей Комов
Участник форума



Joined: 10 Oct 2004
Posts: 54
Карма: 2
   поощрить/наказать


PostPosted: Fri Nov 04, 2005 5:38 pm (спустя 43 минуты; написано за 1 минуту 1 секунду)
   Post subject:
Reply with quote

Я смотрю в этой библиотеке вообще с плейсхолдерами проблемы, все то, что прекрасно описано в набле, здесь совершенно отсутствует. С чем это связано?
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 414
   поощрить/наказать


PostPosted: Sat Nov 05, 2005 1:51 pm (спустя 20 часов 12 минут; написано за 1 минуту 4 секунды)
   Post subject:
Reply with quote

Иван Шумков wrote:
Поечему не сделаете поддержку "родных" placeholder-ов mysql?
Потому что PHP-функции для работы с MySQL не поддерживают placeholder-ы. Нечего поддерживать. :-)
Сергей Владимирович wrote:
с плейсхолдерами проблемы, все то, что прекрасно описано в набле, здесь совершенно отсутствует
Вы преувеличиваете. Есть вставка скалярных placeholder-ов, списков и ассоциативных массивов. Практика показала, что этого вполне достаточно.
Back to top
View user's profile Send private message Send e-mail
Иван Шумков
Участник форума



Joined: 30 Dec 2004
Posts: 229
Карма: 6
   поощрить/наказать

Location: Россия, Санкт-Петербург

PostPosted: Wed Nov 09, 2005 4:29 am (спустя 3 дня 14 часов 37 минут; написано за 5 минут 32 секунды)
   Post subject:
Reply with quote

Дмитрий Котеров wrote:
Потому что PHP-функции для работы с MySQL не поддерживают placeholder-ы. Нечего поддерживать. :-)
А mysqli (ru.php.net/mysqli)?
Дмитрий Котеров wrote:
Есть вставка скалярных placeholder-ов, списков и ассоциативных массивов. Практика показала, что этого вполне достаточно.
Совершенно с вами согласен - функционал Database_Placeholder избыточен.

Возможно было бы не лишним добавить функцию Quote, которая будет эскейпить значения (mysql_real_escape_string) и в зависимоти от параметра еще и обарачивать в одинарные ковычки (по умолчанию оборачивать). И тогда ее можно использовать в методах вашей библиотеки, которые заменяют плэйсхолдеры на значения и код самого продукта, когда просто собираешь sql выражение для какогонибудь класса и т.п.
Back to top
View user's profile Send private message
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 414
   поощрить/наказать


PostPosted: Thu Nov 10, 2005 12:15 pm (спустя 1 день 7 часов 46 минут; написано за 33 секунды)
   Post subject:
Reply with quote

Иван Шумков wrote:
А mysqli
Это только в PHP5.
Иван Шумков wrote:
Возможно было бы не лишним добавить функцию Quote
Она есть: $DB->database->escape().
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 414
   поощрить/наказать


PostPosted: Thu Nov 10, 2005 12:18 pm (спустя 2 минуты)
   Post subject:
Reply with quote


М

Перенесено из форума: Разное :: PHP.
Перенесено в форум: SQL и PHP :: SQL.
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 414
   поощрить/наказать


PostPosted: Thu Nov 10, 2005 4:46 pm (спустя 4 часа 28 минут; написано за 18 секунд)
   Post subject:
Reply with quote

Пишется статья в "Конструкторе". Обсуждение тут:
forum.dklab.ru/comments/lib/6_dbsimpleLaconicWorkWithVariousSubd.html

Last edited by Дмитрий Котеров on Thu Nov 10, 2005 4:48 pm; edited 1 time in total
Back to top
View user's profile Send private message Send e-mail
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 414
   поощрить/наказать


PostPosted: Thu Nov 10, 2005 4:47 pm (спустя 4 секунды)
   Post subject:
Reply with quote


М

Тема закрыта.
Back to top
View user's profile Send private message Send e-mail
Display posts from previous:   
Post new topic   This topic is locked: you cannot edit posts or make replies. All times are GMT + 3 Hours
Goto page Previous  1, 2
Page 2 of 2    Email to a Friend.
You cannot post new topics in this forum. You cannot reply to topics in this forum. You cannot edit your posts in this forum. You cannot delete your posts in this forum. You cannot vote in polls in this forum. You cannot attach files in this forum. You can download files in this forum.
XML